/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Communication;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**Creates {@link Communication.LineGrepper LineGreppers} from a properties file.
 * An instance of LineGrepperFactory is created with a the name of a properties
 * file or a {@link java.util.Properties Properties} object containing key-value
 * pairs that describe one or more LineGrepper pattern sets.
 *
 * A LineGrepper pattern set is described in a properties file with the
 * following format:
 *
 * <PRE>
 * FIRST_PATTERN_SET_1  = first pattern first line
 * FIRST_PATTERN_SET_2  = first pattern second line
 * second_pattern_set_1 = second pattern set first and only line</PRE>
 * 
 * <P>LineGrepperFactory looks for keys with the format &lt;pattern_name&gt;_&lt;line_number&gt;.
 * Then it sorts the keys for each pattern_name by line_number and creates an array
 * of the values corresponding to each key, which will be sorted by the key's line_number.
 * Finally this array is passed into the {@link Communication.LineGrepper LineGrepper} {@link Communication.LineGrepper#LineGrepper(java.lang.String[]) constructor}.</p>
 *
 * <P>Note: remember that regular expression constructs that begin with a backslash (\) must be
 * <b>double escaped</b>, like \\d for the \d construct.</p>
 * 
 * @author Aaron Heise
 */
public class LineGrepperFactory {
    /**The properties object that will be searched for LineGrepper patterns.*/
    Properties properties;

    /**Loads a Properties object from a file.
     *
     * @param filename the name of the file to load from
     * @return the loaded properties object
     * @throws FileNotFoundException file could not be found
     * @throws IOException file could not be read
     */
    protected static Properties loadProperties(String filename) throws FileNotFoundException, IOException {
        Properties p = new Properties();
        p.load(new FileInputStream(filename));
        return p;
    }

    /**Creates a LineGrepperFactory by first loading a properties file from disk
     *
     * @param filename name of the file to load the properties from
     * @throws FileNotFoundException file could not be found
     * @throws IOException file could not be read
     */
    public LineGrepperFactory(String filename) throws FileNotFoundException, IOException {
        this(LineGrepperFactory.loadProperties(filename));
    }

    /**Creates a LineGrepperFactory using a Properties object
     *
     * @param properties Properties object to search for LineGrepper patterns
     */
    public LineGrepperFactory(Properties properties) {
        this.properties = properties;
    }

    /**Creates a LineGrepper with patterns from this instance's properties object that match the supplied grepper name.
     *
     * @param grepperName the name to search the properties object for
     * @return the LineGrepper created with matching properties file entries
     * @throws PatternSyntaxException at least one pattern has an invalid syntax
     */
    public LineGrepper createLineGrepper(String grepperName) throws PatternSyntaxException {
        String[] patterns = this.GetPatternsForGrepper(grepperName, this.properties);
        return new LineGrepper(patterns);
    }

    /**Searches a Properties object for lines matching the format for a given grepper name.
     *
     * @param grepperName the name of the grepper to search for
     * @param properties the properties object to search
     * @return the patterns found for grepperName, sorted by line number.
     */
    protected static String[] GetPatternsForGrepper(String grepperName, Properties properties) {
        Pattern pattern = Pattern.compile("(" + grepperName + ")_(\\d+)");
        Matcher matcher = pattern.matcher("");
        TreeMap<Integer, String> patternMap = new TreeMap<Integer, String>();

        for(Enumeration<Object> keyEnumerator = properties.keys(); keyEnumerator.hasMoreElements();) {
            String key = (String) keyEnumerator.nextElement();
            matcher.reset(key);
            if(matcher.matches()) {
                patternMap.put(new Integer(matcher.group(2)), properties.getProperty(key));
            }
        }

        TreeSet<Integer> keys = new TreeSet<Integer>(patternMap.keySet());
        String[] patterns = new String[keys.size()];
        int i = 0;
        for (Integer key : keys) {
             patterns[i] = patternMap.get(key);
             i++;
        }

        return patterns;
    }
}
